import Axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig, Method } from 'axios'
import type { CustomAxiosRequestConfig } from '@/types/global'
import { ElMessage, ElNotification } from 'element-plus'
import { getToken, removeToken } from '@/utils/auth'
import { APP_ID, CodeMessage, StoreUserKey } from '@/config'
import NProgress from 'nprogress'
import router from '@/router'
import { localRemove } from '.'

export interface BaseResponse<T = any> {
  code: number
  data: T
  message: string
}

const service = Axios.create({
  baseURL: `${import.meta.env.VITE_API_URL as string}/api` || undefined,
  timeout: 50000,
  headers: {
    appid: APP_ID,
  },
})

service.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    NProgress.start()

    const token = getToken()
    if (token) {
      config!.headers!.Authorization = `Bearer ${token}` // 让每个请求携带自定义token
    }

    return config
  },
  (error: { message: string }) => {
    ElMessage.error(error.message)
  }
)
service.interceptors.response.use(
  async (response: AxiosResponse): Promise<any> => {
    const { data } = response
    const { code, message, status } = data
    const errMsg = message || '系统异常，请稍候再试'

    switch (status) {
      case 401:
        localRemove(StoreUserKey)
        removeToken()
        router.push({ name: 'login' })
        break
    }

    if (typeof code !== 'undefined' && code !== 0) {
      ElNotification.error(errMsg)
      return Promise.reject(errMsg)
    }

    NProgress.done()
    return Promise.resolve(data)
  },
  (err: AxiosError) => {
    console.log('error', err)
    NProgress.done()

    const response: any = Object.assign({}, err.response)

    if (!response) return Promise.reject(err)

    let msg = '系统异常，请稍候再试'

    // 处理500类型错误
    if (response?.data?.statusCode) {
      msg = CodeMessage[response?.data?.statusCode]
    }

    // 处理细分错误
    if (response?.data?.error) {
      const error = response?.data?.error
      const txt = Array.isArray(error) ? error.join(',') : error
      msg = CodeMessage[response?.status] || txt
    }

    ElMessage.error(msg)

    return Promise.reject(err)
  }
)

const request = <T = any>(config: CustomAxiosRequestConfig): Promise<T> => {
  return new Promise((resolve, reject) => {
    service
      .request<BaseResponse<T>>(config)
      .then((res: AxiosResponse) => resolve(res.data))
      .catch((err: { message: string }) => reject(err))
  })
}

request.get = <T = any>(url: string, params?: object): Promise<T> =>
  request({
    method: 'get',
    url,
    params,
  })

request.post = <T = any>(url: string, params?: object): Promise<T> =>
  request({
    method: 'post',
    url,
    data: params,
  })

request.delete = <T = any>(url: string, params?: object): Promise<T> =>
  request({
    method: 'delete',
    url,
    params,
  })

request.put = <T = any>(url: string, params?: object): Promise<T> =>
  request({
    method: 'put',
    url,
    data: params,
  })

request.patch = <T = any>(url: string, params?: object): Promise<T> =>
  request({
    method: 'patch',
    url,
    data: params,
  })

// 封装restful
export const fetchRequest = ({ api, id, type = 'get', params }: { api: string; id?: string; type?: Method; params?: any }) => {
  // if (api === 'nav') {
  //   debugger
  // }
  const data = ['get', 'delete'].includes(type as string) ? { params } : { data: params }
  const url = typeof id !== 'undefined' && id?.toString()?.length ? `/${api}/${id}` : `/${api}`
  return request({
    method: type,
    url,
    ...data,
  })
}

export default request
